home *** CD-ROM | disk | FTP | other *** search
- {
- -=> Quoting Sean Graham to All on 22 Jun 94 <=-
- SG> some (efficient, I would hope) code in pascal that will allow me to
- SG> move in a 2D or 3D 'universe' (or more correctly, grid-system). Let me
-
- SG> Let's start out easy. For example, how would I write code to draw a
- SG> line on a 50x80 (yes, ascii chars) screen from pos A(10,5) to pos
- SG> B(47,56)?
- SG> Now imagine that my screen has magically grown a third dimention. So
- SG> I now want to draw a line from pos A(47,34,7) to pos B(21,11,33). How
- SG> would I write code to do that?
-
- SG> Now picture this, I no longer have a screen, but a grid that works
- SG> along the same principles as the screen did, except the points range
- SG> from -20 to +20 on (x,y,z). (That gives me a total of 68,921 (41^3)
- SG> possible co-ordinates.)
- SG> Pretend that Is a universe in space. I'm in a tiny escape pod and
- SG> must get from co-ordinate (-10,+05,+12) to co-ordinate (+07,+02,-11)
-
- If you want to create an actual space, try :
- }
-
- UNIT space;
- { Author: John Howard }
- {
- Define a two-dimensional space representation which is used for Cartesian and
- Polar coordinate systems. A three-dimensional space is for Spherical and
- Azimuth-Elevation coordinate systems.
- }
- { A vector is a one-dimensional array of real numbers. A matrix has two
- dimensions m by n with m rows and n columns. Notice the row number always
- comes first in the dimensions and the indices. Example square matrix A33 =
- [ a11 a12 a13 ] or generally A[i, j]; i=rows, j=columns.
- [ a21 a22 a23 ]
- [ a31 a32 a33 ]
- A matrix can be operated upon with appropriate column or row vectors.
- }
- INTERFACE
- {.$DEFINE D2} {remove period to use 2D}
- {$IFNDEF D2}
- const N = 3; { Cardinality for Three_Vector}
- M = 3; { Square matrix for invert routine}
- {$ELSE}
- const N = 2; { Cardinality for Two_Vector}
- M = 2; { Square matrix for invert routine}
- {$ENDIF}
- Size = M;
- type
- Vector = array [1..N] of real; { 3D vector is the most common! }
- Matrix = array [1..M, 1..N] of real; { 3x3 matrix is the most common! }
-
- {Store all the components into a vector}
- {$IFNDEF D2}
- procedure Set_Value( var a: Vector; x_value, y_value, z_value: real);
- {$ELSE}
- procedure Set_Value( var a: Vector; x_value, y_value: real);
- {$ENDIF}
-
- {Retrieve the value of s from the ith element of a vector}
- function Element( var a: Vector; i: integer): real;
-
- {Retrieve the first element from a vector}
- function X_Component( var a: Vector): real;
-
- {Retrieve the second element from a vector}
- function Y_Component( var a: Vector): real;
-
- {Retrieve the third element from a vector}
- {$IFNDEF D2}
- function Z_Component( var a: Vector): real;
- {$ENDIF}
-
- IMPLEMENTATION
-
- procedure Set_Value; { Note: parameter list intentionally left off}
- begin
- a[1] := x_value;
- a[2] := y_value;
- {$IFNDEF D2}
- a[3] := z_value;
- {$ENDIF}
- end;
-
- function Element( var a: Vector; i: integer): real;
- begin
- Element := a[i];
- end;
-
- function X_Component( var a: Vector): real;
- begin
- X_Component := a[1];
- end;
-
- function Y_Component( var a: Vector): real;
- begin
- Y_Component := a[2];
- end;
-
- {$IFNDEF D2}
- function Z_Component( var a: Vector): real;
- begin
- Z_Component := a[3];
- end;
- {$ENDIF}
- BEGIN
- END.
-
- (**********
- If you do not want to create an actual 3d space, just convert coordinates :
-
- You could use a two dimensional X_Component and Y_Component calculation to get
- you to an approximate region based upon Z_Component. Example:
-
- From point A(x1,y1) to B(x2,y2) you travel a distance = sqrt(sqr(x2-x1) +
- sqr(y2-y1)) at a slope of (y2-y1)/(x2-x1). That slope is called the Tangent
- of the angle of inclination of the line AB.
-
- Now that you know where you are heading and how far away it is you can divide
- the total distance into sections say of unit length. That means a distance of
- 10 would have ten units. Every time your spaceship moves one unit in the known
- direction you can reverse the calculation to find out where you are at. When
- you reach the final distance, you'd take approximations using the third
- component. This idea is simple but not very accurate in the interum space.
-
- You can use the same idea but implement it with a proper coordinate conversion.
- **********)
-
- UNIT coord;
- { Author: John Howard }
- { Original source: Jack Crenshaw, 1992 Embedded Systems Programming }
- { Space Conversion -- Angles are capitalized }
- { All axes are perpendicular to each other }
- INTERFACE
- const
- Zero = 0.0;
- One = 1.0;
- TwoPi = Two * SYSTEM.Pi;
- Pi_Over_Two = SYSTEM.Pi/Two;
-
- { 1 binary angular measure = 1 pirad = Pi radians = 180 degrees }
- Degrees_Per_Radian = 180.0/SYSTEM.Pi;
- Radians_Per_Degree = SYSTEM.Pi/180.0;
-
- { X-axis points east, y-axis north, and angle Theta is the heading measured
- north of due east. If Theta is zero that corresponds to a line running
- along the x-axis a radial distance of r.
- }
- Procedure To_Polar ( x, y: real; Var r, Theta: real);
- Procedure From_Polar ( r, Theta: real; Var x, y: real);
-
- { X-axis points toward you, y-axis right, z-axis upward, angle Phi measures
- directions in the horizontal (x-y plane) from the x-axis, and angle Theta
- measures the direction in the vertical from the z-axis downward. If Theta
- is zero that corresponds to a line pointed up the z-axis.
- }
- Procedure To_Spherical ( x, y, z: real; Var r, Phi, Theta: real);
- Procedure From_Spherical ( r, Phi, Theta: real; Var x, y, z: real);
-
- { X-axis points east, y-axis north, z-axis upward, angle Phi corresponds to an
- azimuth measured clockwise from due north, and angle Theta is the elevation
- measured upwards from the horizon (x-y plane).
- }
- Procedure To_Azimuth_Elevation ( x, y, z: real; Var r, Phi, Theta: real);
- Procedure From_Azimuth_Elevation ( r, Phi, Theta: real; Var x, y, z: real);
-
- Function Sign ( x, y: real): real;
- Function Degrees ( A: real): real;
- Function Radians ( A: real): real;
-
- Function Atan ( x: real): real; {ArcTangent}
- Function Atan2 ( s, c: real): real;
-
- IMPLEMENTATION
-
- { Convert from Cartesian to polar coordinates }
- Procedure To_Polar ( x, y: real; Var r, Theta: real);
- Begin
- r := Sqrt(Sqr(x) + Sqr(y));
- Theta := Atan2(y, x);
- End;
-
- { Convert from polar to Cartesian coordinates }
- Procedure From_Polar ( r, Theta: real; Var x, y: real);
- Begin
- x := r * Cos(Theta);
- y := r * Sin(Theta);
- End;
-
- { Convert from Cartesian to spherical polar coordinates }
- Procedure To_Spherical ( x, y, z: real; Var r, Phi, Theta: real);
- var temp: real;
- Begin
- To_Polar(x, y, temp, Phi);
- To_Polar(z, temp, r, Theta);
- End;
-
- { Convert from spherical polar to Cartesian coordinates }
- Procedure From_Spherical ( r, Phi, Theta: real; Var x, y, z: real);
- var temp: real;
- Begin
- From_Polar(r, Theta, z, temp);
- From_Polar(temp, Phi, x, y);
- End;
-
- { Convert from Cartesian to Az-El coordinates }
- Procedure To_Azimuth_Elevation ( x, y, z: real; Var r, Phi, Theta: real);
- var temp: real;
- Begin
- To_Polar(y, x, temp, Phi);
- To_Polar(temp, z, r, Theta);
- End;
-
- { Convert from Az-El to Cartesian coordinates }
- Procedure From_Azimuth_Elevation ( r, Phi, Theta: real; Var x, y, z: real);
- var temp: real;
- Begin
- From_Polar(r, Theta, temp, z);
- From_Polar(temp, Phi, y, x);
- End;
-
- { Returns Absolute value of x with Sign of y }
- Function Sign ( x, y: real): real;
- Begin
- if y >= Zero then
- Sign := Abs(x)
- else
- Sign := -Abs(x);
- End;
-
- { Convert angle from radians to degrees }
- Function Degrees ( A: real): real;
- Begin
- Degrees := Degrees_Per_Radian * A;
- End;
-
- { Convert angle from degrees to radians }
- Function Radians ( A: real): real;
- Begin
- Radians := Radians_Per_Degree * A;
- End;
-
- { Inverse Trigonometric Tangent Function }
- Function Atan ( x: real): real;
- { Arctangent algorithm uses fifth-order rational fraction with optimized
- coefficients
- }
- function _Atan ( x: real): real;
- const
- a = 0.999999447;
- b = 0.259455937;
- c = 0.592716128;
-
- var y: real;
- begin
- y := x*x;
- _Atan := a*x*( One + b*y) / ( One + c*y);
- end;
-
- var a, y: real;
- Begin
- y := Abs(x);
- if y <= One then
- a := _Atan(y)
- else
- a := Pi_Over_Two - _Atan( One / y);
- if x <= Zero then
- a := -a;
- Atan := a;
- End;
-
- { Four-Quadrant Inverse Trigonometric Tangent Function }
- Function Atan2 ( s, c: real): real;
- var s1, c1, Theta: real;
- Begin
- s1 := Abs(s);
- c1 := Abs(c);
- if c1 + s1 = Zero then
- Theta := Zero
- else if s1 <= c1 then
- Theta := ArcTan(s1 / c1)
- else
- Theta := Pi_Over_Two - ArcTan(c1 / s1);
- if c < Zero then
- Theta := Pi - Theta;
- Atan2 := Sign(Theta, s);
- End;
- BEGIN
- END.
- (*****END*****)